﻿-- $Revision$
local L = LibStub("AceLocale-3.0"):GetLocale("BunchOfBars")

local BunchOfBars = BunchOfBars

local SharedMedia     = LibStub("LibSharedMedia-3.0")
local SharedMediaTypeStatusBar = SharedMedia.MediaType and SharedMedia.MediaType.STATUSBAR or "statusbar"
local SharedMediaTypeFont = SharedMedia.MediaType and SharedMedia.MediaType.FONT or "font"
local path = "Interface\\AddOns\\BunchOfBars\\Textures\\"

for i=1,21 do
	SharedMedia:Register(SharedMediaTypeStatusBar, "bar"..i, path .. "bar"..i)
end

local fonts = {}
local statusbars = {}
for _, n in pairs(SharedMedia:List(SharedMediaTypeFont)) do
	fonts[SharedMedia:Fetch(SharedMediaTypeFont, n)] = n
end
for _, n in pairs(SharedMedia:List(SharedMediaTypeStatusBar)) do
	statusbars[SharedMedia:Fetch(SharedMediaTypeStatusBar, n)] = n
end


sorts = {
	["NAME"]  = L["Name"],
	["INDEX"] = L["Index"]
}
groupbys = {
	["CLASS"] = L["Class"],
	["GROUP"] = L["Group"],
	["NONE"]  = L["None"]
}
positions = {
	["TOPLEFT"] = L["TopLeft"],
	["TOPRIGHT"] = L["TopRight"],
	["BOTTOMLEFT"] = L["BottomLeft"],
	["BOTTOMRIGHT"] = L["BottomRight"]
}
positions_i = {
	L["Outside"],
	L["Inside"],
}
positions_r = {
	[1] = { ["TOPLEFT"] = "TOPRIGHT", 
		["TOPRIGHT"] = "TOPLEFT",
		["BOTTOMLEFT"] = "BOTTOMRIGHT",
		["BOTTOMRIGHT"] = "BOTTOMLEFT"
		},
	[2] = { ["TOPLEFT"] = {"TOPRIGHT", "BOTTOMLEFT"},
		["TOPRIGHT"] = {"TOPLEFT", "BOTTOMRIGHT"},
		["BOTTOMLEFT"] = {"BOTTOMRIGHT", "TOPLEFT"},
		["BOTTOMRIGHT"] = {"BOTTOMLEFT", "TOPRIGHT"},
		}
}
justify_H = {
	["LEFT"] = L["Left"],
	["CENTER"] = L["Center"],
	["RIGHT"] = L["Right"]
}
justify_V = {
	["TOP"] = L["Top"],
	["MIDDLE"] = L["Middle"],
	["BOTTOM"] = L["Bottom"]
}
local partyhidden = false -- blizzard party frames are shown by default

BunchOfBars.options = {
	name = "BunchOfBars",
	type = "group",
	childGroups = "tree",
	handler = BunchOfBars,
	args = {
		visual = {
			type     = "group",
			name     = L["Visual Options"],
			desc     = L["Options to control the looks of BunchOfBars."],
			disabled = function() return InCombatLockdown() end,
			order	 = 1,
			args     = {
				update = {
					type  = "execute",
					name  = L["Update"],
					desc  = L["Update everything."],
					func  = "ForceUpdate",
					order = 1
				},
				recreate = {
					type  = "execute",
					name  = L["Recreate"],
					desc  = L["Recreate all frames."],
					func  = "reCreate",
					order = 1
				},

				header2 = { type = "header", name = " ", order = 2 },

				reset = {
					type     = "execute",
					name     = L["Reset Position"],
					desc     = L["Move BunchOfBars to the middle of the screen."],
					func     = "ResetPosition",
					order    = 3
				},
				scale = {
					type = "range",
					name = L["Scale"],
					desc = L["The scale of the frames."],
					min  = 0.5,
					max  = 2,
					step = 0.1,
					get  = "GetSetScale",
					set  = "GetSetScale",
					order    = 4
				},
				yoffest = {
					type = "range",
					name = L["Offest"],
					desc = L["The padding between each the frames."],
					min  = 1,
					max  = 30,
					step = 1,
					get  = "GetSetYOffest",
					set  = "GetSetYOffest",
					order    = 5
				},
				columnspacing = {
					type = "range",
					name = L["Column Spacing"],
					desc = L["The spacing between each column."],
					min  = 50,
					max  = 400,
					step = 2,
					get  = "GetSetColumnSpacing",
					set  = "GetSetColumnSpacing",
					order    = 6
				},

				header5 = { type = "header", name = " ", order = 7 },

				solo = {
					type = "toggle",
					name = L["Show when solo"],
					desc = L["Show BunchOrBars when your on your own."],
					get  = "GetSetSolo",
					set  = "GetSetSolo",
					order = 8
				},
				party = {
					type = "toggle",
					name = L["Party"],
					desc = L["Show BunchOrBars when your in a party."],
					get  = "GetSetParty",
					set  = "GetSetParty",
					order = 9
				},
				hideparty = {
					type  = "toggle",
					name  = L["Hide Blizzard Party"],
					desc  = L["Hide the Bilzzard party frames."],
					get   = "GetSetHideParty",
					set   = "GetSetHideParty",
					order = 10
				},

				header8 = { type = "header", name = " ", order = 11 },

				groupby = {
					type  = "select",
					name  = L["Group by"],
					desc  = L["Group players in your raid by Group or Class."],
					values = groupbys,
					get = "GetSetGroupBy",
					set = "GetSetGroupBy",
					order = 12
				},
				sortby = {
					type  = "select",
					name  = L["Sort by"],
					desc  = L["Sort the player in a group by Name or Index."],
					values = sorts,
					get = "GetSetSort",
					set = "GetSetSort",
					order = 13
				},
				orderstr = {
					type  = "input",
					name  = L["Order by"],
					desc  = L["How to order the groups."],
					usage = L["[1-8, STRING] a comma seperated list of raid group numbers and/or class names"],
					get   = "GetSetOrderStr",
					set   = "GetSetOrderStr",
					order = 14
				},
				filterstr = {
					type  = "input",
					name  = L["Filter by"],
					desc  = L["Only show the players or groups and/or classes on this filter list."],
					usage = L["[1-8, STRING] a comma seperated list of player names or raid group numbers and/or class names.\nEmpty for no filter"],
					get   = "GetSetFilterStr",
					set   = "GetSetFilterStr",
					order = 15
				},

				header13 = { type = "header", name = " ", order = 16 },

				width = {
					type = "range",
					name = L["Width"],
					desc = L["Width of the frame."],
					min = 50,
			       		max = 300,
			       		step = 1,
			       		get = "GetSetWidth",
			       		set = "GetSetWidth",
					order = 17
				},
				height = {
					type = "range",
					name = L["Height"],
					desc = L["Height of the frame."],
					min = 10,
			       		max = 50,
			       		step = 1,
			       		get = "GetSetHeight",
			       		set = "GetSetHeight",
					order = 18
				},
				bgtransparent = {
					type = "range",
					name = L["Set BG transparent"],
					desc = L["Set frame's background slightly transparent."],
					min  = 0.1,
		            		max  = 1,
		            		step = 0.1,
		            		get  = "GetSetBGT",
		            		set  = "GetSetBGT",
					order = 19
				},

				header14 = { type = "header", name = " ", order = 20 },

				players = {
					type  = "range",
					name  = L["Players per Column"],
					desc  = L["Number of players per column."],
					min   = 1,
					max   = 40,
					step  = 1,
					get   = "GetSetPlayers",
					set   = "GetSetPlayers",
					order = 21
				},
			}
		},
		module = {
			type = "group",
			name = L["Module Options"],
			desc = L["Options for all enabled modules."],
			order = 2,
			args = {}
		},
		minimap = {
			type = "toggle",
			name = L["Minimap icon"],
			desc = L["Toggle the minimap icon."],
			get = "GetSetMMicon",
			set = "GetSetMMicon",
			order = 22,
		}
	}
}

BunchOfBars.defaults = {
	profile = {
		visual = {
			locked = false,
			x      = 400,
			y      = 400,

			padding = 5,
			leftpadding = 5,
			rightpadding = 5,
			leftscale = 1.1,
			rightscale = 1,

			scale = 1,

			solo	  = true,
			party = true,
			hideparty = false,

			bgtransparent = 0.4,

			groupby   = "GROUP",
			sortby    = "INDEX",
			orderstr  = "1,2,3,4,5,6,7,8",
			filterstr = nil,
			players = 20,
		},
		minimap = {
			hide = false,
		},
		style = {
			width = 100,
			height = 30,
			yoffest = 4,
			columnspacing = 150,
		}
	}
}

function BunchOfBars:RegisterModulesOptions()
	for name,module in self:IterateModules() do
		if not module.db then
			module.db = self.db:RegisterNamespace(name, module.defaultDB)
		end
		if module.options then
			self.options.args.module.args[name] = {
				type    = "group",
				handler = module,
				name    = module.options and module.options.name or name,
				desc    = string.format(L["Options for %s."], module.options and module.options.name or name),
				args    = module.options and module.options.args or {}
			}
			if module.moduletype == "font" then
				if module.db.profile.fonts.font == "" then module.db.profile.fonts.font = SharedMedia:Fetch(SharedMediaTypeFont,SharedMedia:GetDefault(SharedMediaTypeFont)) end
				self.options.args.module.args[name].args.fonts = {
					type = "group",
					name = L["Fonts"],
					desc = string.format(L["Fonts for %s"], name),
					order = 1,
					get = function(info) return module.db.profile.fonts[info[#info]] end,
					set = function(info, value) 
							module.db.profile.fonts[info[#info]] = value
							module:SetFont()
					      end,
					args = {
						font = {
							type = "select",
							name = L["Fonts"],
							desc = L["Change font"],
							values = fonts,
							order = 1,
						},
						size = {
							type = "range",
							name = L["Font Size"],
							desc = L["Change font size"],
							min = 6,
							max = 30,
							step = 1,
							order = 5,
						},
						justifyH = {
							type = "select",
							name = L["Justify H"],
							desc = L["Set justify of horizontal"],
							values = justify_H,
							order = 10,
						},
						justifyV = {
							type = "select",
							name = L["Justify V"],
							desc = L["Set justify of vertical"],
							values = justify_V,
							order = 15,
						}
					}
				}
			elseif module.moduletype == "icon" then
				self.options.args.module.args[name].args["iconsize"] = {
					type = "range",
					name = L["Icon Size"],
					desc = L["Set the icons size."],
					get  = function() return module.db.profile.iconsize end,
					set  = function(_, v)
							module.db.profile.iconsize = v
							module:SetIconSize()
						end,
					min = 5,
					max = 30,
					step = 1,
				}				
			elseif module.moduletype == "statusbar" then
				self.options.args.module.args[name].args["texture"] = {
					type = "select",
					name = L["Texture"],
					desc = L["Set the texture of bar."],
					get  = function() return module.db.profile.texture end,
					set  = function(_, v)
							module.db.profile.texture = v
							module:SetTexture()
						end,
					values = statusbars,
					order = 1
				}
				self.options.args.module.args[name].args["ltr"] = {
					type = "toggle",
					name = L["LtR"],
					desc = L["Toggles if the bar depletes from left to right top to bottom."],
					get  = function() return module.db.profile.ltr end,
					set  = function(_, v)
							module.db.profile.ltr = v
							module:SetTexture()
						end,
					order = 2
				}
				self.options.args.module.args[name].args["vertical"] = {
					type = "toggle",
					name = L["Vertical"],
					desc = L["Toggles if change the bar from horizontal to vertical."],
					get  = function() return module.db.profile.vertical end,
					set  = function(_, v)
							module.db.profile.vertical = v
							module:SetTexture()
						end,
					order = 3
				}
			end
			if module.db.profile.style then
				self.options.args.module.args[name].args.style = {
					type = "group",
					name = L["Style"],
					desc = string.format(L["Style for %s"], name),
					order = 1,
					get = function(info) return module.db.profile.style[info[#info]] end,
					set = function(info, value) 
							module.db.profile.style[info[#info]] = value
							BunchOfBars:UpdateLayouts()
					      end,
					args = { }
				}
				if module.db.profile.style.position then
					self.options.args.module.args[name].args.style.args.position = {
						type = "select",
						name = L["Position"],
						desc = string.format(L["Position of the %s."], name),
						values = positions,
						order = 10
					}
				end
				if module.db.profile.style.inout then
					self.options.args.module.args[name].args.style.args.inout = {
						type = "select",
						name = L["In or Out"],
						desc = string.format(L["Select %s at inside or outside of core frame"], name),
						values = InOut(name),
						order = 20
					}
				end
				if module.db.profile.style.xof then
					self.options.args.module.args[name].args.style.args.xof = {
						type = "range",
						name = L["X Offest"],
						desc = L["Set x-axis offest."],
						min = -100,
						max = 100,
						step = 1,
						order = 30
					}
				end
				if module.db.profile.style.yof then
					self.options.args.module.args[name].args.style.args.yof = {
						type = "range",
						name = L["Y Offest"],
						desc = L["Set y-axis offest."],
						min = -100,
						max = 100,
						step = 1,
						order = 30
					}
				end
				if module.db.profile.style.width then
					self.options.args.module.args[name].args.style.args.width = {
						type = "range",
						name = L["Width"],
						desc = string.format(L["Set width of %s."],name),
						min = 0,
						max = self.db.profile.style.width,
						step = 1,
						order = 40
					}
				end
				if module.db.profile.style.height then
					self.options.args.module.args[name].args.style.args.height = {
						type = "range",
						name = L["Height"],
						desc = string.format(L["Set height of %s."],name),
						min = 0,
						max = self.db.profile.style.height,
						step = 1,
						order = 50
					}
				end
				if module.db.profile.style.strata then
					self.options.args.module.args[name].args.style.args.strata = {
						type = "range",
						name = L["Strata"],
						desc = string.format(L["Set frame strata of %s."],name),
						min = 1,
						max = 20,
						step = 1,
						order = 60
					}
				end
			end
		end
	end
end

----------------------------------
--      Option Handlers         --
----------------------------------

function BunchOfBars:GetSetPadding(s, v)
	if type(v) == "nil" then 
		if s == "left" then
			return self.db.profile.visual.leftpadding
		elseif s == "right" then
			return self.db.profile.visual.rightpadding
		end
	end

	if self.db.profile.visual.leftpadding ~= v and s == "left" then
		self.db.profile.visual.leftpadding = v
	elseif self.db.profile.visual.rightpadding ~= v and s == "right" then
		self.db.profile.visual.rightpadding = v
	end
end

function BunchOfBars:GetSetScale(_, v)
	if type(v) == "nil" then return self.db.profile.visual.scale end

	-- this check is to assure we don't update to often
	if self.db.profile.visual.scale ~= v then
		self.db.profile.visual.scale = v
		
		self:PositionAndScale()
	end
end


function BunchOfBars:GetSetParty(_, v)
	if type(v) == "nil" then return self.db.profile.visual.party end

	if self.db.profile.visual.party ~= v then
		self.db.profile.visual.party = v
		
		self.master:SetAttribute("showParty", self.db.profile.visual.party)
		self:SetModuleConfig()
	end
end


function BunchOfBars:GetSetSolo(_, v)
	if type(v) == "nil" then return self.db.profile.visual.solo end

	if self.db.profile.visual.solo ~= v then
		self.db.profile.visual.solo = v
		
		self.master:SetAttribute("showSolo", self.db.profile.visual.solo)
		self:SetModuleConfig()
	end
end


function BunchOfBars:GetSetHideParty(_, v)	
	if type(v) == "nil" then return self.db.profile.visual.hideparty end

	if self.db.profile.visual.hideparty ~= v then
		self.db.profile.visual.hideparty = v

		self:HideShowParty()
	end
end


function BunchOfBars:GetSetGroupBy(_, v)
	if type(v) == "nil" then return self.db.profile.visual.groupby end

	if self.db.profile.visual.groupby ~= v then
		self.db.profile.visual.groupby = v

		if self.db.profile.visual.groupby == "CLASS" then
			self.db.profile.visual.orderstr = "WARRIOR,DRUID,PALADIN,DEATHKNIGHT,PRIEST,SHAMAN,ROGUE,MAGE,WARLOCK,HUNTER"
		elseif self.db.profile.visual.groupby == "GROUP" then
			self.db.profile.visual.orderstr = "1,2,3,4,5,6,7,8"
		end

		self.master:SetAttribute("groupBy", (self.db.profile.visual.groupby == "NONE") and nil or self.db.profile.visual.groupby)
		self.master:SetAttribute("groupingOrder", self.db.profile.visual.orderstr)
		self:SetModuleConfig()
	end
end


function BunchOfBars:GetSetSort(_, v)	
	if type(v) == "nil" then return self.db.profile.visual.sortby end

	if self.db.profile.visual.sortby ~= v then
		self.db.profile.visual.sortby = v

		self.master:SetAttribute("sortMethod", self.db.profile.visual.sortby)
		self:SetModuleConfig()
	end
end


function BunchOfBars:GetSetOrderStr(_, v)
	if type(v) == "nil" then return self.db.profile.visual.orderstr end

	if self.db.profile.visual.orderstr ~= v then
		self.db.profile.visual.orderstr = string.upper(v)

		self.master:SetAttribute("groupBy", (self.db.profile.visual.groupby == "NONE") and nil or self.db.profile.visual.groupby)
		self.master:SetAttribute("groupingOrder", self.db.profile.visual.orderstr)
		self:SetModuleConfig()
	end
end


function BunchOfBars:GetSetFilterStr(_, v)
	if type(v) == "nil" then return self.db.profile.visual.filterstr or "" end

	if self.db.profile.visual.filterstr ~= v then
		self.db.profile.visual.filterstr = v

		if self.db.profile.visual.filterstr == "" then
			self.db.profile.visual.filterstr = nil
			self.master:SetAttribute("groupFilter", nil)
			self.master:SetAttribute("nameList"   , nil)
		else
			local s = string.upper(self.db.profile.visual.filterstr)
			local hasclass, hasgroup = false, false

			if string.find(s, "%d") then
				hasgroup = true
			end

			if string.find(s, "WARRIOR") or
			   string.find(s, "DEATHKNIGHT") or
			   string.find(s, "DRUID") or
			   string.find(s, "PALADIN") or
			   string.find(s, "PRIEST") or
			   string.find(s, "SHAMAN") or
			   string.find(s, "ROGUE") or
			   string.find(s, "MAGE") or
			   string.find(s, "WARLOCK") or
			   string.find(s, "HUNTER") then
			   hasclass = true
			end

			if hasgroup or hasclass then
				self.db.profile.visual.filterstr = s
				self.master:SetAttribute("groupFilter", self.db.profile.visual.filterstr)
				self.master:SetAttribute("strictFiltering", (hasgroup and hasclass) and true or false)
				self.master:SetAttribute("nameList"   , nil)
			else
				self.master:SetAttribute("groupFilter"    , nil)
				self.master:SetAttribute("strictFiltering", false)
				self.master:SetAttribute("nameList"       , self.db.profile.visual.filterstr)
			end
		end
		self:SetModuleConfig()
	end
end


function BunchOfBars:GetSetPlayers(_, v)
	if type(v) == "nil" then return self.db.profile.visual.players end

	if self.db.profile.visual.players ~= v then
		self.db.profile.visual.players = v

		self.master:SetAttribute("maxColumns", ceil(40 / self.db.profile.visual.players))
		self.master:SetAttribute("unitsPerColumn", self.db.profile.visual.players)
		self:SetModuleConfig()
	end
end

function BunchOfBars:GetSetYOffest(_, v)
	if type(v) == "nil" then return self.db.profile.style.core.yoffest end

	if self.db.profile.style.core.yoffest ~= v then
		self.db.profile.style.core.yoffest = v

		self.master:SetAttribute("yOffset", - self.db.profile.style.core.yoffest)
		self:SetModuleConfig()

	end
end
function BunchOfBars:GetSetColumnSpacing(_, v)
	if type(v) == "nil" then return self.db.profile.style.core.columnspacing end

	if self.db.profile.style.core.columnspacing ~= v then
		self.db.profile.style.core.columnspacing = v

		self.master:SetAttribute("columnSpacing", self.db.profile.style.core.columnspacing)
		self:SetModuleConfig()
	end
end
function BunchOfBars:GetSetPartyScale(_, v)
	if type(v) == "nil" then return self.db.profile.visual.party.scale end

	if self.db.profile.visual.party.scale ~= v then
		self.db.profile.visual.party.scale = v

		self:PositionAndScale()
	end
end
function BunchOfBars:GetSetHeight(_, v)
	if type(v) == "nil" then return self.db.profile.visual.height end

	if self.db.profile.visual.height ~= v then
		self.db.profile.visual.height = v

		self:UpdateLayouts()
	end
end
function BunchOfBars:GetSetWidth(_, v)
	if type(v) == "nil" then return self.db.profile.visual.width end

	if self.db.profile.visual.width ~= v then
		
		self.db.profile.visual.width = v
		
		for _,frame in pairs(self.frames) do
			frame:SetWidth(self.db.profile.visual.width)
		end
		self:SetModuleConfig()
	end
end
function BunchOfBars:GetSetHeight(_, v)
	if type(v) == "nil" then return self.db.profile.visual.height end

	if self.db.profile.visual.height ~= v then
		
		self.db.profile.visual.height = v
		
		for _,frame in pairs(self.frames) do
			frame:SetHeight(self.db.profile.visual.height)
		end
		self:SetModuleConfig()
	end
end

function BunchOfBars:GetSetMMicon(_, v)
	if type(v) == "nil" then return not self.db.profile.minimap.hide end

	if self.db.profile.minimap.hide == v then
		self.db.profile.minimap.hide = not v
	
		if self.db.profile.minimap.hide then
			mmicon:Hide("BunchOfBars")
		else
			mmicon:Show("BunchOfBars")
		end
	end
end
function BunchOfBars:GetSetBGT(_, v)
	if type(v) == "nil" then return self.db.profile.visual.bgtransparent end

	if self.db.profile.visual.bgtransparent ~= v then
		self.db.profile.visual.bgtransparent = v
		
		for _,frame in pairs(self.frames) do
			frame:SetBackdropColor(0, 0, 0, self.db.profile.visual.bgtransparent)
		end
		for name,is in pairs(self.Header) do
		if is then
			local module = self:GetModule(name)
			for _,frame in pairs(module.frames) do
				frame:SetBackdropColor(0, 0, 0, self.db.profile.visual.bgtransparent)
			end
		end
	end

	end
end
function BunchOfBars:reCreate()
	self:NewMaster()
--[[	for name,is in pairs(self.Header) do
		if is then
			module:CreateGroup()
		end
	end
]]
end
function BunchOfBars:OnProfileConfig()
	self:CreateMaster()
	if mmicon then
		mmicon:Refresh("BunchOfBars", ldb, self.db.profile.minimap)
		if self.db.profile.minimap.hide then
			mmicon:Hide("BunchOfBars")
		end
	end
	for name,module in self:IterateModules() do
		if self:IsEnabled(module) then
			module:OnEnable()
		end
	end
end
function InOut(name)
	local list = positions_i
	if BunchOfBars.master[name] then
		list[2] = nil
	end
	return list
end